package com.socket;

import com.alibaba.fastjson.JSON;
import com.enums.ProjectStatusEnum;
import com.os.OS;
import com.scan.JavaFileScanner;
import com.utils.WebSocketJsonData;
import com.utils.WebSocketReceiveJsonData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.File;
import java.io.IOException;

/**
 * 用于运行普通java项目，支持在lib目录下加入jar包
 * @author rkc
 * @date 2022/8/29 15:09
 */
@Slf4j
@Component
@ServerEndpoint("/api/v1/java/run/{token}/{projectName}/{mainClass}")
public class JavaRunnerWebSocket extends RunnerWebSocket {

    /**
     * 打开连接请求运行
     * @param session 连接session
     * @param token token
     * @param projectName 运行的项目
     * @param mainClass 运行的入口类，如"\\test4\\src\\main\\java\\com\\ServerApplication.java"
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token, @PathParam("projectName") String projectName, @PathParam("mainClass") String mainClass) {
        currentSession = session;
        log.info("{}加入连接", session.getId());
        mainClass = mainClass.replace("&", File.separator);
        //得到项目和启动类的物理路径
        String projectPath = fileMappingUtil.mapping(token, projectName), mainClassPath = fileMappingUtil.mapping(token, mainClass);
        log.info("项目物理路径：{}，启动类物理路径：{}", projectPath, mainClassPath);
        setStartExec(projectPath, mainClassPath);
        try {
            currentProcess = Runtime.getRuntime().exec(cmdArray);
            log.info("{}准备启动", mainClassPath);
            startProcess(session);
        } catch (IOException e) {
            log.error(e.getMessage());
            sendMessage(new WebSocketJsonData(ProjectStatusEnum.FAILED_STARTED, e.getMessage(), null), session);
        }
    }

    private void handleDependencies(File lib, StringBuilder javacLibs, StringBuilder javaLibs) {
        if (lib.exists()) {
            char sep = OS.isWindows() ? ';' : ':';
            File[] fs = lib.listFiles();
            boolean flag = false;
            if (fs != null) {
                for (File f : fs) {
                    if (!"jar".equals(f.getName().substring(f.getName().lastIndexOf('.') + 1))) {
                        if (!flag) {
                            javacLibs.append("-cp .");
                            javaLibs.append("-cp .");
                            flag = true;
                        }
                        javacLibs.append(String.format("%clib%s%s", sep, File.separator, f.getName()));
                        javaLibs.append(String.format("%c..%slib%s%s", sep, File.separator, File.separator, f.getName()));
                    }
                }
            }
        }
    }

    private void setStartExec(String projectPath, String mainClassPath) {
        JavaFileScanner jfs = new JavaFileScanner(projectPath);
        StringBuilder sb = new StringBuilder();
        for (File javaFile : jfs.getJavaFiles()) {
            sb.append(javaFile.getAbsolutePath().substring(projectPath.length() + 1)).append(" ");
        }
        //去除项目路径前缀和src前缀
        String javaPath = mainClassPath.substring(projectPath.length() + 6).replace(File.separator, ".");
        javaPath = javaPath.substring(0, javaPath.lastIndexOf('.'));
        //如果有lib目录，说明有jar，命令也需要修改
        File lib = new File(projectPath + File.separator + "lib");
        StringBuilder javacLibs = new StringBuilder(), javaLibs = new StringBuilder();
        handleDependencies(lib, javacLibs, javaLibs);
        if (OS.isWindows()) {
            String disk = projectConfig.getStorage().substring(0, projectConfig.getStorage().indexOf(":") + 1);
            cmdArray[2] = disk + " && cd " + projectPath + " && javac -d out " + sb + javacLibs + " && cd out && java " + javaLibs + " " + javaPath;
        } else if (OS.isLinux()) {
            cmdArray[2] = "cd " + projectPath + " && javac -d out " + sb + javacLibs + " && cd out && java " + javaLibs + " " + javaPath;
        }
        log.info("执行命令{}", cmdArray[2]);
    }

    @OnClose
    public void onClose(Session session) {
        log.info("{}关闭了连接", session.getId());
        if (currentProcess != null && currentProcess.isAlive()) {
            stopProcess(getPidList(), session);
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到{}的消息{}", session.getId(), message);
        WebSocketReceiveJsonData data = JSON.parseObject(message, WebSocketReceiveJsonData.class);
        if (data.getCode() == ProjectStatusEnum.COMMAND_INPUT.getCode()) {
            String s = (String) data.getData();
            if ("stop".equals(s)) {
                stopProcess(getPidList(), session);
            }
        } else if (data.getCode() == ProjectStatusEnum.CONTENT_INPUT.getCode()) {
            //输入参数
            String s = (String) data.getData();
            log.info("接收到输入的参数：{}", s);
            writeText(s);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("id={}发生了错误", session.getId());
        if (currentProcess != null && currentProcess.isAlive()) {
            stopProcess(getPidList(), session);
        }
        error.printStackTrace();
    }
}
